"""
公共方法管理路由
提供公共方法的CRUD操作API
"""
import os
import json
from flask import Blueprint, request, jsonify, render_template, current_app
from flask_login import login_required, current_user
from werkzeug.utils import secure_filename
from sqlalchemy import or_, and_
from ...shared.models import db, CommonMethod, CommonMethodUsage, User
from ...shared.log_utils import log_user_action
from ..auth import admin_required

common_methods_bp = Blueprint('common_methods', __name__)

# 允许的文件扩展名
ALLOWED_EXTENSIONS = {'py'}

def allowed_file(filename):
    """检查文件扩展名是否允许"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@common_methods_bp.route('/common-methods')
@login_required
def common_methods_page():
    """公共方法管理页面"""
    return render_template('dashboard/common_methods.html')

@common_methods_bp.route('/api/common-methods', methods=['GET'])
@login_required
def get_common_methods():
    """获取公共方法列表"""
    try:
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 20, type=int)
        search = request.args.get('search', '')
        show_public = request.args.get('show_public', 'false').lower() == 'true'
        
        # 构建查询
        query = CommonMethod.query
        
        # 搜索条件
        if search:
            query = query.filter(or_(
                CommonMethod.name.contains(search),
                CommonMethod.description.contains(search)
            ))
        
        # 权限过滤 - 确保用户只能看到自己的方法或公开的方法
        if show_public:
            # 显示公开的方法（其他用户创建的公开方法）
            query = query.filter(
                CommonMethod.is_public == True, 
                CommonMethod.is_active == True,
                CommonMethod.user_id != current_user.id  # 排除自己的方法，避免重复
            )
        else:
            # 默认只显示当前用户的方法
            query = query.filter(CommonMethod.user_id == current_user.id)
        
        # 排序
        query = query.order_by(CommonMethod.updated_at.desc())
        
        # 分页
        pagination = query.paginate(
            page=page, 
            per_page=per_page, 
            error_out=False
        )
        
        methods = [method.to_dict() for method in pagination.items]
        
        return jsonify({
            'success': True,
            'data': {
                'methods': methods,
                'pagination': {
                    'page': page,
                    'per_page': per_page,
                    'total': pagination.total,
                    'pages': pagination.pages,
                    'has_prev': pagination.has_prev,
                    'has_next': pagination.has_next
                }
            }
        })
        
    except Exception as e:
        current_app.logger.error(f"获取公共方法列表失败: {str(e)}")
        return jsonify({'success': False, 'message': f'获取公共方法列表失败: {str(e)}'}), 500

@common_methods_bp.route('/api/common-methods/<int:method_id>', methods=['GET'])
@login_required
def get_common_method(method_id):
    """获取单个公共方法详情"""
    try:
        method = CommonMethod.query.get_or_404(method_id)
        
        # 权限检查
        if method.user_id != current_user.id and not method.is_public:
            return jsonify({'success': False, 'message': '无权限访问此方法'}), 403
        
        return jsonify({
            'success': True,
            'data': method.to_dict(include_content=True)
        })
        
    except Exception as e:
        current_app.logger.error(f"获取公共方法详情失败: {str(e)}")
        return jsonify({'success': False, 'message': f'获取公共方法详情失败: {str(e)}'}), 500

@common_methods_bp.route('/api/common-methods', methods=['POST'])
@login_required
def create_common_method():
    """创建公共方法"""
    try:
        data = request.get_json()
        
        # 检查数据是否为空
        if data is None:
            return jsonify({'success': False, 'message': '请求数据为空或格式错误'}), 400
        
        # 验证必填字段
        required_fields = ['name', 'content']
        for field in required_fields:
            if not data.get(field):
                return jsonify({'success': False, 'message': f'缺少必填字段: {field}'}), 400
        
        # 检查方法名是否已存在
        existing = CommonMethod.query.filter_by(
            user_id=current_user.id,
            name=data['name']
        ).first()
        
        if existing:
            return jsonify({'success': False, 'message': '方法名已存在'}), 400
        
        # 创建公共方法，使用方法名作为模块名
        method = CommonMethod(
            name=data['name'],
            module_name=data['name'],  # 使用方法名作为模块名
            description=data.get('description', ''),
            content=data['content'],
            user_id=current_user.id,
            is_public=data.get('is_public', False),
            tags=json.dumps(data.get('tags', []))
        )
        
        db.session.add(method)
        db.session.commit()
        
        # 创建文件系统中的文件
        _save_method_to_file(method)
        
        # 记录日志
        log_user_action(
            level='INFO',
            module='common_methods',
            message=f'创建公共方法: {method.name}',
            user_id=current_user.id,
            action='create_common_method',
            resource_type='common_method',
            resource_id=method.id,
            details=f'创建公共方法: {method.name}'
        )
        
        return jsonify({
            'success': True,
            'message': '公共方法创建成功',
            'data': method.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"创建公共方法失败: {str(e)}")
        return jsonify({'success': False, 'message': f'创建公共方法失败: {str(e)}'}), 500

@common_methods_bp.route('/api/common-methods/<int:method_id>', methods=['PUT'])
@login_required
def update_common_method(method_id):
    """更新公共方法"""
    try:
        method = CommonMethod.query.get_or_404(method_id)
        
        # 权限检查
        if method.user_id != current_user.id:
            return jsonify({'success': False, 'message': '无权限修改此方法'}), 403
        
        data = request.get_json()
        
        # 检查方法名是否与其他方法冲突
        if data.get('name') and data['name'] != method.name:
            existing = CommonMethod.query.filter_by(
                user_id=current_user.id,
                name=data['name']
            ).first()
            
            if existing:
                return jsonify({'success': False, 'message': '方法名已存在'}), 400
        
        # 更新字段
        if data.get('name'):
            method.name = data['name']
            method.module_name = data['name']  # 模块名跟随方法名更新
        if 'description' in data:
            method.description = data['description']
        if data.get('content'):
            method.content = data['content']
        if 'is_public' in data:
            method.is_public = data['is_public']
        if 'is_active' in data:
            method.is_active = data['is_active']
        if 'tags' in data:
            method.tags = json.dumps(data['tags'])
        
        db.session.commit()
        
        # 更新文件系统中的文件
        _save_method_to_file(method)
        
        # 记录日志
        log_user_action(
            level='INFO',
            module='common_methods',
            message=f'更新公共方法: {method.name}',
            user_id=current_user.id,
            action='update_common_method',
            resource_type='common_method',
            resource_id=method.id,
            details=f'更新公共方法: {method.name}'
        )
        
        return jsonify({
            'success': True,
            'message': '公共方法更新成功',
            'data': method.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"更新公共方法失败: {str(e)}")
        return jsonify({'success': False, 'message': f'更新公共方法失败: {str(e)}'}), 500

@common_methods_bp.route('/api/common-methods/<int:method_id>', methods=['DELETE'])
@login_required
def delete_common_method(method_id):
    """删除公共方法"""
    try:
        method = CommonMethod.query.get_or_404(method_id)
        
        # 权限检查
        if method.user_id != current_user.id:
            return jsonify({'success': False, 'message': '无权限删除此方法'}), 403
        
        method_name = method.name
        
        # 删除文件系统中的文件
        _delete_method_file(method)
        
        # 删除数据库记录
        db.session.delete(method)
        db.session.commit()
        
        # 记录日志
        log_user_action(
            level='INFO',
            module='common_methods',
            message=f'删除公共方法: {method_name}',
            user_id=current_user.id,
            action='delete_common_method',
            resource_type='common_method',
            resource_id=method_id,
            details=f'删除公共方法: {method_name}'
        )
        
        return jsonify({
            'success': True,
            'message': '公共方法删除成功'
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"删除公共方法失败: {str(e)}")
        return jsonify({'success': False, 'message': f'删除公共方法失败: {str(e)}'}), 500

@common_methods_bp.route('/api/common-methods/upload', methods=['POST'])
@login_required
def upload_common_method():
    """上传公共方法文件"""
    try:
        if 'file' not in request.files:
            return jsonify({'success': False, 'message': '没有选择文件'}), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'success': False, 'message': '没有选择文件'}), 400
        
        if not allowed_file(file.filename):
            return jsonify({'success': False, 'message': '只允许上传.py文件'}), 400
        
        # 读取文件内容
        content = file.read().decode('utf-8')
        
        # 获取其他参数
        name = request.form.get('name', file.filename.rsplit('.', 1)[0])
        description = request.form.get('description', '')
        is_public = request.form.get('is_public', 'false').lower() == 'true'
        
        # 检查方法名是否已存在
        existing = CommonMethod.query.filter_by(
            user_id=current_user.id,
            name=name
        ).first()
        
        if existing:
            return jsonify({'success': False, 'message': '方法名已存在'}), 400
        
        # 创建公共方法
        method = CommonMethod(
            name=name,
            module_name=name,  # 模块名与方法名相同
            description=description,
            content=content,
            user_id=current_user.id,
            is_public=is_public
        )
        
        db.session.add(method)
        db.session.commit()
        
        # 创建文件系统中的文件
        _save_method_to_file(method)
        
        # 记录日志
        log_user_action(
            level='INFO',
            module='common_methods',
            message=f'上传公共方法: {method.name}',
            user_id=current_user.id,
            action='upload_common_method',
            resource_type='common_method',
            resource_id=method.id,
            details=f'上传公共方法: {method.name}'
        )
        
        return jsonify({
            'success': True,
            'message': '文件上传成功',
            'data': method.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"上传公共方法失败: {str(e)}")
        return jsonify({'success': False, 'message': f'上传公共方法失败: {str(e)}'}), 500

@common_methods_bp.route('/api/common-methods/<int:method_id>/usage', methods=['POST'])
@login_required
def record_method_usage(method_id):
    """记录公共方法使用"""
    try:
        method = CommonMethod.query.get_or_404(method_id)
        
        # 权限检查
        if method.user_id != current_user.id and not method.is_public:
            return jsonify({'success': False, 'message': '无权限使用此方法'}), 403
        
        data = request.get_json()
        task_id = data.get('task_id')
        
        # 记录使用
        usage = CommonMethodUsage(
            method_id=method_id,
            user_id=current_user.id,
            task_id=task_id
        )
        
        db.session.add(usage)
        
        # 增加使用次数
        method.increment_usage()
        
        return jsonify({
            'success': True,
            'message': '使用记录已保存'
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"记录方法使用失败: {str(e)}")
        return jsonify({'success': False, 'message': f'记录方法使用失败: {str(e)}'}), 500


def _save_method_to_file(method):
    """将公共方法保存到文件系统"""
    try:
        # 从配置中获取公共方法目录
        from config.config import Config
        common_methods_dir = Config.COMMON_METHODS_DIR
        
        # 如果是相对路径，需要转换为绝对路径
        if not os.path.isabs(common_methods_dir):
            # 获取项目根目录（当前工作目录）
            project_root = os.getcwd()
            common_methods_dir = os.path.join(project_root, common_methods_dir)
        
        # 创建用户目录
        user_dir = os.path.join(common_methods_dir, method.user.username)
        os.makedirs(user_dir, exist_ok=True)
        
        # 创建用户目录的__init__.py文件
        init_file = os.path.join(user_dir, '__init__.py')
        if not os.path.exists(init_file):
            with open(init_file, 'w', encoding='utf-8') as f:
                f.write('# 用户公共方法模块\n')
        
        # 保存文件，文件名就是方法名
        file_path = os.path.join(user_dir, f"{method.name}.py")
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(method.content)
        
        current_app.logger.info(f"公共方法文件已保存: {file_path}")
            
    except Exception as e:
        current_app.logger.error(f"保存公共方法文件失败: {str(e)}")
        raise

def _delete_method_file(method):
    """删除公共方法文件"""
    try:
        # 从配置中获取公共方法目录
        from config.config import Config
        common_methods_dir = Config.COMMON_METHODS_DIR
        
        # 如果是相对路径，需要转换为绝对路径
        if not os.path.isabs(common_methods_dir):
            # 获取项目根目录（当前工作目录）
            project_root = os.getcwd()
            common_methods_dir = os.path.join(project_root, common_methods_dir)
        
        user_dir = os.path.join(common_methods_dir, method.user.username)
        file_path = os.path.join(user_dir, f"{method.name}.py")
        
        if os.path.exists(file_path):
            os.remove(file_path)
            current_app.logger.info(f"公共方法文件已删除: {file_path}")
            
    except Exception as e:
        current_app.logger.error(f"删除公共方法文件失败: {str(e)}")
        # 不抛出异常，因为数据库删除更重要